package descentFly.away3D4
{
	import away3d.containers.ObjectContainer3D;
	import away3d.entities.Mesh;
	import away3d.loaders.parsers.data.DefaultBitmapData;
	import away3d.materials.BitmapMaterial;
	import away3d.materials.ColorMaterial;
	import away3d.materials.DefaultMaterialBase;
	import away3d.materials.MaterialBase;
	import away3d.materials.SkyBoxMaterial;
	import away3d.materials.methods.EnvMapAmbientMethod;
	import away3d.materials.methods.EnvMapMethod;
	import away3d.materials.methods.FresnelEnvMapMethod2;
	import away3d.materials.methods.ShadingMethodBase;
	import away3d.materials.utils.CubeMap;
	import away3d.primitives.SkyBox;
	import away3d.vf.managers.awayLoadSection;
	
	import descentFly.away3D4.material.df_UVAnimMaterial;
	import descentFly.data.df_fields;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	
	import space.sp_utils;

	public class df_awayUtils {
		public static function createMaterial(params: Object, retFunc: Function, createIsNull: Function=null): void {
			var result: MaterialBase;
			if (params && params.Class) createMaterialFromOptions(params.Class, params.options, retFunc);
			else if (retFunc != null) retFunc(createIsNull());
		}
		
		public static function createMaterialMethods(material: DefaultMaterialBase, methods: Array, retFunc: Function): void {
			var count: int = 0;
			for (var i: int=0; i< methods.length; i++) {
				count++;
				createMaterialMethod(methods[i].Class, methods[i].options, function(method: ShadingMethodBase): void {
					count--;
					material.addMethod(method);
					if ((count == 0) && (i >= methods.length - 1)) retFunc();
				});
			}
		}
		
		private static function getAlpha(options: Object): Number {
			return options.hasOwnProperty(df_fields.FIELD_ALPHA)?options.alpha:1;
		}
		
		public static function createMaterialMethod(methodClass: Class, options: Object, retFunc: Function): void {
			
			function loadCubeMap(cbm_retFunc: Function): void {
				var ls: df_loadSection = new df_loadSection();
				var skyBox: SkyBox = ls.loadSkyBox(options.patternURL);
				ls.endSection(function(): void {
					cbm_retFunc((skyBox.material as SkyBoxMaterial).cubeMap);
				});
			}
			
			if (methodClass == EnvMapMethod) {
				loadCubeMap(function(cubeMap: CubeMap): void {
					retFunc(new EnvMapMethod(cubeMap, getAlpha(options)));
				});
			} else if (methodClass == FresnelEnvMapMethod2) {
				loadCubeMap(function(cubeMap: CubeMap): void {
					var fem: FresnelEnvMapMethod2 = new FresnelEnvMapMethod2(cubeMap, getAlpha(options));
					fem.fresnelPower = options.fresnelPower?options.fresnelPower:0.9;
					retFunc(fem);
				});
			}
		}

		private static function createMaterialFromOptions(materialClass: Class, options: Object, retFunc: Function): void {
			function applyParamsRet(result: DefaultMaterialBase): void {
				if (options.propertys)
					for (var prop: String in options.propertys) {
						result[prop] = options.propertys[prop];
					}
				if (result && options.methods)
					createMaterialMethods(result, options.methods, function(): void {
						retFunc(result);
					});
				else retFunc(result);
			}
			
			var result: DefaultMaterialBase;
			if ((materialClass == BitmapMaterial) || 
				(materialClass == df_UVAnimMaterial)) {
				var bm: BitmapMaterial 	= new materialClass();
				var ls: df_loadSection 	= new df_loadSection();
				var bmp: Bitmap = ls.loadBmp(options.URL, true);
				ls.endSection(function(): void {
					bm.bitmapData 		= bmp.bitmapData;
					bm.alphaBlending	= options.transparent;
					applyParamsRet(bm);
				});
				result = bm;
			} else {
				if (materialClass == ColorMaterial) {
					result = new ColorMaterial(options.color, options.hasOwnProperty(df_fields.FIELD_ALPHA)?options.alpha:1);
				}
				applyParamsRet(result);
			}
		}
		
		public static function objectByName(parent: ObjectContainer3D, a_name: String): ObjectContainer3D {
			for (var i:int=0; i<parent.numChildren; i++) {
				var child: ObjectContainer3D = parent.getChildAt(i);
				if (child.originalName == a_name) return child;
			}
			return null;			
		}
		
		public static function applyMaterialOptionsFromModel(model: ObjectContainer3D, options: Object, retFunc: Function): void {
			if (options.hasOwnProperty('animElementIndex')) {
				df_awayUtils.createMaterial(options.material, function(material: df_UVAnimMaterial): void {
					var cyl: Mesh = model.getChildAt(options.animElementIndex) as Mesh;
					if (cyl && material) {
						cyl.material = material;
						material.beginAnimation(cyl.subMeshes[0]);
					}
					retFunc();
				});
			} else  if (options.hasOwnProperty(df_fields.FIELD_MATERIAL)) {
				df_awayUtils.createMaterial(options.material, function(material: DefaultMaterialBase): void {
					var cyl: Mesh = model.getChildAt(0) as Mesh;
					if (cyl && material) cyl.material = material;
					retFunc();
				});
			} if (options.hasOwnProperty(df_fields.FIELD_MATERIALS)) {
				var loaded: int = options.materials.length;
				options.materials.forEach(function(item: Object, i: int, arr: Array): void {
					createMaterial(item.material, function(material: DefaultMaterialBase): void {
						var meshes: Array = item[df_fields.FIELD_MESHES].split(',');
						meshes.forEach(function(item: String, i: int, arr: Array): void {
							var obj: Mesh = objectByName(model, item) as Mesh;
							obj.material = material;
						});
						loaded--;
						if (loaded == 0) retFunc();
					});
				});
			} else retFunc();			
		}
	}
}